package com.ruoyi.qywx.getway.request;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.utils.NumberUtils;
import com.ruoyi.common.utils.StrUtils;
import com.ruoyi.common.utils.http.OkHttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.qywx.service.inters.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.URIBuilder;

import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Map;

/**
 * @author : hcl
 * @Date : 2023/8/7
 */
@Slf4j
public class TxRequest {
    public static final String TX_API_DOMEN = "https://qyapi.weixin.qq.com";
    public static final String ERR_CODE = "errcode";
    public static final String ACCESS_TOKEN = "access_token";

    private static final int MAX_RETRY = 1;
    private final String corpId;
    private final String corpSecret;
    private final TokenService tokenService;
    private int retry = 0;

    private TxRequest(String corpId, String corpSecret) {
        this.corpId = corpId;
        this.corpSecret = corpSecret;
        this.tokenService = SpringUtils.getBean("qywxTokenService");
    }

    public static TxRequest getInstance(String corpId, String corpSecret) {
        return new TxRequest(corpId, corpSecret);
    }

    public TxResponse get(String uri) {
        return get(uri, null);
    }

    public TxResponse get(String url, Map<String, String> body) {
        String err;
        try {
            String data = OkHttpUtils.getInstance().getData(tokenURL(url), body);
            JSONObject json = JSONUtil.parseObj(data);
            if (needRetry(json)) {
                return get(url, body);
            }
            return new TxResponse(!NumberUtils.isTrue(json.getInt(ERR_CODE)), json);
        } catch (Exception e) {
            log.error("请求失败: {}", e.getMessage(), e);
            err = e.getMessage();
        }
        return TxResponse.error(err);
    }

    public TxResponse post(String uri, Map<String, Object> body) {
        return post(uri, body == null ? StrUtils.EMPTY_JSON : JSONUtil.toJsonStr(body));
    }

    public TxResponse post(String uri, String jsonData) {
        String err;
        try {
            String data = OkHttpUtils.getInstance()
                    .postJsonSync(tokenURL(uri), null, jsonData);
            JSONObject json = JSONUtil.parseObj(data);
            if (needRetry(json)) {
                return post(uri, jsonData);
            }
            return new TxResponse(!NumberUtils.isTrue(json.getInt(ERR_CODE)), json);
        } catch (Exception e) {
            log.error("请求失败: {}", e.getMessage(), e);
            err = e.getMessage();
        }
        return TxResponse.error(err);
    }

    public TxResponse uploadFile(String uri, String type, String fileName, byte[] file) {
        String err;
        try {
            String data = OkHttpUtils.getInstance()
                    .PostFileDataSync(tokenURL(uri),
                            Collections.singletonMap("type", type),
                            getFileName(type, fileName),
                            file);
            JSONObject json = JSONUtil.parseObj(data);
            if (needRetry(json)) {
                return uploadFile(uri, type, fileName, file);
            }
            return new TxResponse(!NumberUtils.isTrue(json.getInt(ERR_CODE)), json);
        } catch (Exception e) {
            e.printStackTrace();
            err = e.getMessage();
        }
        return TxResponse.error(err);
    }

    private String getFileName(String type, String fileName) {
        if (StrUtils.isNotEmpty(fileName)) {
            return fileName;
        }
        return type + "_" + RandomUtil.randomString(5);
    }

    private String tokenURL(String url) throws URISyntaxException {
        String toekn = this.tokenService.getToken(this.corpId, this.corpSecret);
        return new URIBuilder(TX_API_DOMEN + url).addParameter(ACCESS_TOKEN, toekn).build().toString();
    }

    private boolean needRetry(JSONObject json) {
        int errcode = json.getInt(ERR_CODE);
        if (log.isDebugEnabled()) {
            log.debug("企业微信接口返回数据:{}", json);
        }
        if (NumberUtils.isTrue(errcode)) { // 舍弃拦截器，直接在返回的时候判断是否需要重试
            if (errcode == 42001 && retry < MAX_RETRY) { // token 过期重试一次
                clearPastToken();
                retry++;
                return true;
            }
            log.error("QYWX_API  corpId:{} errCode:{} 请求失败:{}",
                    this.corpId,
                    errcode,
                    json.getStr("errmsg"));
        }
        return false;
    }

    private void clearPastToken() {
        this.tokenService.clearPastToken(this.corpId, this.corpSecret);
    }
}
